#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ReconstructionURL= "";
    SceneURL= "";

    // Creamos el dialogo de configuracion de la entrada RAW y lo conectamos a este widget
    LoadSetup= new LoadRawDialog();
    connect(LoadSetup, SIGNAL(BuildModel(QString, VObject::NORMALMODE, int,int,int,int,int,int,int,int,int)),
            this, SLOT(BuildMCObject(QString, VObject::NORMALMODE, int,int,int,int,int,int,int,int,int)));
    connect(ui->ViewPort, SIGNAL(WrongThreshold()), this, SLOT(WrongThreshold()));
    connect(ui->ViewPort, SIGNAL(ReconstructionInfo(int,QString,int,int,int,int,int)),
            this, SLOT(ShowReconstructionInfo(int,QString,int,int,int,int,int)));

    connect(ui->ViewPort->Controller, SIGNAL(cameraMoves(QVector3D)), this, SLOT(updateStatusBar(QVector3D)));

    // Conectamos todos los controles entre el widget de OpenGL y este
    connect(ui->ViewPort, SIGNAL(AnaglyphChanged(bool)), this, SLOT(UpdateAnaglyphSwitch(bool)));
    connect(ui->AnaglyphInput, SIGNAL(clicked(bool)), ui->ViewPort, SLOT(SwitchAnaglyph(bool)));
    connect(ui->CyanButton, SIGNAL(clicked(bool)), ui->ViewPort, SLOT(SwitchCyanAnaglyph(bool)));
    connect(ui->ViewPort, SIGNAL(CyanAnaglyphChanged(bool)), this, SLOT(SwitchCyanBlueAnaglyph(bool)));
    connect(ui->ZeroParallaxInput, SIGNAL(valueChanged(double)), ui->ViewPort, SLOT(SetZeroParallax(double)));
    connect(ui->EyeDistanceInput, SIGNAL(valueChanged(double)), ui->ViewPort, SLOT(SetEyeDistance(double)));
    connect(ui->ShowWireFrameInput, SIGNAL(clicked(bool)), ui->ViewPort, SLOT(SwitchWireFrame(bool)));
    connect(ui->OverlayWireFrameInput, SIGNAL(clicked(bool)), ui->ViewPort, SLOT(SwitchOverlayWireFrame(bool)));
    connect(ui->ViewPort, SIGNAL(LeftPanelSwitched()), this, SLOT(SwitchLeftPanel()));
    connect(ui->ViewPort, SIGNAL(RightPanelSwitched()), this, SLOT(SwitchRightPanel()));
    connect(ui->ViewPort, SIGNAL(ParticleSystemAdded(QString)), this, SLOT(InsertParticleSystem(QString)));

    // Preparamos los campos de informacion de reconstruccion
    ui->DataSetNameInput->setEnabled(false);
    ui->ObjSizeInput->setEnabled(false);
    ui->DimensionsInput->setEnabled(false);
    ui->BitDepthInput->setEnabled(false);
    ui->PoligonCountInput->setEnabled(false);
    ui->VertexCountInput->setEnabled(false);
    ui->IsovalueInput->setEnabled(false);
    ui->ElapsedInput->setEnabled(false);
    ui->ReconstructionInformation->hide();

    // Opciones
    ui->LeftPanel->hide();
    ui->RightPanel->hide();
    ui->EyeDistanceInput->hide();
    ui->EyeDistantLabel->hide();

    // Escondemos los controles del left panel
    ui->SizeOptions->hide();
    ui->SourceOptions->hide();
    ui->DirOptions->hide();
    ui->StepOptions->hide();
    ui->TTLOptions->hide();
    ui->BlendingOptions->hide();

    // Datos utiles a la aplicacion
    IconDir= "../src/icons/";

    this->showMaximized();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::updateStatusBar(QVector3D cameraPos)
{
    statusBar()->showMessage(QString("Camera Pos: %1 %2 %3").arg(cameraPos.x()).arg(cameraPos.y()).arg(cameraPos.z()), 2000);
}

void MainWindow::UpdateAnaglyphSwitch(bool value)
{
    ui->AnaglyphInput->setChecked(value);
}

void MainWindow::SwitchCyanBlueAnaglyph(bool value)
{
    ui->CyanButton->setChecked(value);
}

// Esta funcion sera llamada cuando el usuario quiera reconstruir un dataset
void MainWindow::on_actionMCBuildObject_triggered()
{
    QString FileURL= QFileDialog::getOpenFileName(this,
                                                  "Importar archivo...",
                                                  "../");

    if (FileURL!="")
    {
        ReconstructionURL= FileURL;

        qDebug("getOpenFileName says: %s", FileURL.toStdString().c_str());

        QStringList AuxTokens= ReconstructionURL.split("/");
        ShortReconstructionURL= AuxTokens.at(AuxTokens.size()-1);

        LoadSetup->CleanThis();
        LoadSetup->SetURL(FileURL);
        LoadSetup->show();
    }
}

// Esta funcion recibira la configuracion de reconstruccion para empezar con el algoritmo
void MainWindow::BuildMCObject (QString URL, VObject::NORMALMODE normcalc, int xsize, int ysize, int zsize,
                    int bitdepth,
                    int isovalue,
                    int maxpoligon,
                    int xmax, int ymax, int zmax)
{
    // Primero limpiamos la interfaz
    ui->DataSetNameInput->setText("");
    ui->ObjSizeInput->setText("");
    ui->DimensionsInput->setText("");
    ui->BitDepthInput->setText("");
    ui->PoligonCountInput->setText("");
    ui->VertexCountInput->setText("");
    ui->IsovalueInput->setText("");
    ui->ElapsedInput->setText("");

    // Actualizamos nuestros datos
    MCxsize= xsize;
    MCysize= ysize;
    MCzsize= zsize;
    MCBitDepth= bitdepth;
    MCIsovalue= isovalue;
    MCMaxPoligon= maxpoligon;
    MCxmax= xmax;
    MCymax= ymax;
    MCzmax= zmax;
    MCNormCalc= normcalc;

    // A reconstruir el objeto!
    ui->ViewPort->LoadRAW(URL,
                          MCNormCalc,
                          xsize, ysize, zsize,
                          bitdepth,
                          isovalue,
                          maxpoligon,
                          xmax, ymax, zmax);
}

// Esta funcion sera llamada al finalizar exitosamente la reconstrucction
void MainWindow::ShowReconstructionInfo (int size, QString dimensions, int bitdepth, int poligoncount,
                             int vertexcount, int isovalue, int elapsed)
{
    ui->DataSetNameInput->setText(ShortReconstructionURL);
    ui->ObjSizeInput->setText(QString("%1 bytes").arg(size));
    ui->DimensionsInput->setText(dimensions);
    ui->BitDepthInput->setText(QString("%1").arg(bitdepth));
    ui->PoligonCountInput->setText(QString("%1").arg(poligoncount));
    ui->VertexCountInput->setText(QString("%1").arg(vertexcount));
    ui->IsovalueInput->setText(QString("%1").arg(isovalue));
    ui->ElapsedInput->setText(QString("%1").arg(elapsed));
    ui->ReconstructionInformation->show();
}

// Esta funcion sera llamada si se excede el numero maximo de poligonos indicado por el usuario
void MainWindow::WrongThreshold()
{
    QMessageBox* InfMessage= new QMessageBox();

    InfMessage->setWindowTitle("Notificación");
    InfMessage->setText("Wrong threshold!");
    InfMessage->setIcon(QMessageBox::Information);
    InfMessage->setInformativeText("Se ha excedido el numero máximo de polígonos indicado, la reconstrucción se detuvo.");

    InfMessage->show();
}

// Esta funcion reconstruira el objeto con un nuevo isovalue
void MainWindow::on_RebuildButton_clicked()
{
    MCIsovalue= ui->NewIsovalueInput->value();

    // A reconstruir el objeto!
    ui->ViewPort->LoadRAW(ReconstructionURL,
                          MCNormCalc,
                          MCxsize, MCysize, MCzsize,
                          MCBitDepth,
                          MCIsovalue,
                          MCMaxPoligon,
                          MCxmax, MCymax, MCzmax);
}


void MainWindow::on_UpsideDownButton_clicked()
{
    ui->ViewPort->UpsideDownMC();
}

void MainWindow::on_GoUpButton_clicked()
{
    ui->ViewPort->MoveMC(1);
}

void MainWindow::on_GoDownButton_clicked()
{
    ui->ViewPort->MoveMC(-1);
}

void MainWindow::on_GoLeftButton_clicked()
{
    ui->ViewPort->MoveMC(2);
}

void MainWindow::on_GoRightButton_clicked()
{
    ui->ViewPort->MoveMC(-2);
}

// Esto se activara cuando el usuario desee cargar una escena
void MainWindow::on_actionCargar_escena_triggered()
{
    QString FileURL= QFileDialog::getOpenFileName(this,
                                                  "Escoger archivo de Escena...",
                                                  "../", "*.bdv");

    if (FileURL!="")
    {
        SceneURL= FileURL;

        qDebug("getOpenFileName says: %s", FileURL.toStdString().c_str());

        // Limpiemos las cosas
        ui->SystemList->clear();

        ui->ViewPort->SetScene(FileURL);
    }
}

// Esto se activara cuando el usuario desee recargar la escena actual
void MainWindow::on_actionRecargar_escena_triggered()
{
    if (SceneURL!= "")
    {
        qDebug("getOpenFileName says: %s", SceneURL.toStdString().c_str());

        // Limpiemos las cosas
        ui->SystemList->clear(); // <-- lista de sistemas de particulas en la interfaz!
        ui->ViewPort->SetScene(SceneURL);
    }
    else
        qDebug("SceneURL: %c", SceneURL.toStdString().c_str());
}

/** Submenu de objetos **/
void MainWindow::SwitchLeftPanel()
{
    if (ui->LeftPanel->isVisible())
        ui->LeftPanel->hide();
    else
        ui->LeftPanel->show();
}

/** Submenu de la escena **/
void MainWindow::SwitchRightPanel()
{
    if (ui->RightPanel->isVisible())
        ui->RightPanel->hide();
    else
        ui->RightPanel->show();
}

/** Submenu de particulas **/
// Añadir un sistema de particulas
void MainWindow::InsertParticleSystem(QString input)
{
    ui->SystemList->addItem(input);
    ui->SystemList->setCurrentIndex(ui->SystemList->count() - 1);

    //LoadParticleSystemData(input);
}

// Esconder/ mostrar opciones de particulas
void MainWindow::on_ToggleParticleMenu_clicked()
{
    if (ui->ParticleOptions->isVisible())
    {
        ui->ParticleOptions->hide();
        ui->ToggleParticleMenu->setText("Mostrar");
    }
    else
    {
        ui->ParticleOptions->show();
        ui->ToggleParticleMenu->setText("Esconder");
    }
}

// Esconder/ mostrar opciones de velocidad
void MainWindow::on_ToggleStep_clicked()
{
    if (ui->StepOptions->isVisible())
    {
        ui->ToggleStep->setIcon(QIcon(IconDir + "show.jpg"));
        ui->StepOptions->hide();
    }
    else
    {
        ui->ToggleStep->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->StepOptions->show();
    }
}

// Esconder/ mostrar opciones de origen
void MainWindow::on_ToggleSource_clicked()
{
    if (ui->SourceOptions->isVisible())
    {
        ui->ToggleSource->setIcon(QIcon(IconDir + "show.jpg"));
        ui->SourceOptions->hide();
    }
    else
    {
        ui->ToggleSource->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->SourceOptions->show();
    }
}

// Esconder/ mostrar opciones de direccion
void MainWindow::on_ToggleDir_clicked()
{
    if (ui->DirOptions->isVisible())
    {
        ui->ToggleDir->setIcon(QIcon(IconDir + "show.jpg"));
        ui->DirOptions->hide();
    }
    else
    {
        ui->ToggleDir->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->DirOptions->show();
    }
}

// Esconder/ mostrar opciones de tamaño
void MainWindow::on_ToggleSize_clicked()
{
    if (ui->SizeOptions->isVisible())
    {
        ui->ToggleSize->setIcon(QIcon(IconDir + "show.jpg"));
        ui->SizeOptions->hide();
    }
    else
    {
        ui->ToggleSize->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->SizeOptions->show();
    }
}

// Esconder/ mostrar opciones de ttl
void MainWindow::on_ToggleTTL_clicked()
{
    if (ui->TTLOptions->isVisible())
    {
        ui->ToggleTTL->setIcon(QIcon(IconDir + "show.jpg"));
        ui->TTLOptions->hide();
    }
    else
    {
        ui->ToggleTTL->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->TTLOptions->show();
    }
}

// Esconder / mostrar opciones de blending
void MainWindow::on_ToggleBlending_clicked()
{
    if (ui->BlendingOptions->isVisible())
    {
        ui->ToggleBlending->setIcon(QIcon(IconDir + "show.jpg"));
        ui->BlendingOptions->hide();
    }
    else
    {
        ui->ToggleBlending->setIcon(QIcon(IconDir + "hide.jpg"));
        ui->BlendingOptions->show();
    }
}


// Esta funcion cargara en los controles toda la info correspondiente al sistema
// de particulas escogido
void MainWindow::LoadParticleSystemData(QString input)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(input);

    if (P!= NULL)
    {
        // Como lo hemos encontrado, vamos a cargar sus propiedades
        float* aux= new float [3];

        // Cantidad
        ui->AmountInput->setValue(P->getAmount());

        // Step / velocidad
        ui->StepSizeInput->setValue(P->getStepSize());
        ui->StepVarInput->setValue(P->getStepVar());

        // Source
        aux= P->getSourcePosition();
        ui->SourceXInput->setValue(aux[0]);
        ui->SourceYInput->setValue(aux[1]);
        ui->SourceZInput->setValue(aux[2]);

        aux= P->getSourceVar();
        ui->SourceVarXInput->setValue(aux[0]);
        ui->SourceVarYInput->setValue(aux[1]);
        ui->SourceVarZInput->setValue(aux[2]);

        // Start Color
        aux= P->getStartColor();
        aux= P->getStartColorVar();

        // Direction
        aux= P->getDir();
        ui->DirXInput->setValue(aux[0]);
        ui->DirYInput->setValue(aux[1]);
        ui->DirZInput->setValue(aux[2]);

        aux= P->getDirVar();
        ui->DirVarXInput->setValue(aux[0]);
        ui->DirVarYInput->setValue(aux[1]);
        ui->DirVarZInput->setValue(aux[2]);

        // Size
        aux= P->getSize();
        ui->SizeXInput->setValue(aux[0]);
        ui->SizeYInput->setValue(aux[1]);
        ui->SizeZInput->setValue(aux[2]);

        aux= P->getSizeVar();
        ui->SizeVarXInput->setValue(aux[0]);
        ui->SizeVarYInput->setValue(aux[1]);
        ui->SizeVarZInput->setValue(aux[2]);

        // Time To Live
        ui->TTLInput->setValue(P->getTimeToLive());
        ui->TTLVarInput->setValue(P->getTimeToLiveVar());

        // Amount
        ui->AmountInput->setValue(P->getAmount());

        // Textura
        ui->TextureInput->setText(P->getTextureURL());

        // Blending
        ui->SrcBlendingInput->setCurrentIndex(P->getSrcBlending());
        ui->DstBlendingInput->setCurrentIndex(P->getDstBlending());
        ui->AlphaFunctionInput->setCurrentIndex(P->getAlphaFunction());
        ui->AlphaRefInput->setValue(P->getAlphaReference());
    }
    else
        printf("ERROR: Sistema de particulas no encontrado.\n");
}


void MainWindow::on_SystemList_currentIndexChanged(const QString &input)
{
    LoadParticleSystemData(input);
}

// Esto reconstruira el sistema de particulas con las opciones actuales
void MainWindow::on_RebuildSystemButton_clicked()
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL) P->BuildSystem();
    else printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto alterara la cantidad de particulas en el sistema actual
void MainWindow::on_AmountInput_valueChanged(int arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setAmount(arg1);
        ui->AmountInput->setSingleStep(int(float(arg1*0.1)));
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el step size del sistema de particulas actual
void MainWindow::on_StepSizeInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setStepSize(arg1);
        ui->StepSizeInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto alterara el step var del sistema de particulas actual
void MainWindow::on_StepVarInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setStepVar(arg1);
        ui->StepVarInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el origen en X del sistema de particulas actual
void MainWindow::on_SourceXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourcePosition(arg1, ui->SourceYInput->value(), ui->SourceZInput->value());
        ui->SourceXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el origen en Y del sistema de particulas actual
void MainWindow::on_SourceYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourcePosition(ui->SourceXInput->value(), arg1, ui->SourceZInput->value());
        ui->SourceYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el origen en Z del sistema de particulas actual
void MainWindow::on_SourceZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourcePosition(ui->SourceXInput->value(), ui->SourceYInput->value(), arg1);
        ui->SourceZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en X del sistema de particulas actual
void MainWindow::on_SourceVarXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourceVar(arg1, ui->SourceVarYInput->value(), ui->SourceVarZInput->value());
        ui->SourceVarXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en Y del sistema de particulas actual
void MainWindow::on_SourceVarYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourceVar(ui->SourceVarXInput->value(), arg1, ui->SourceVarZInput->value());
        ui->SourceVarYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en Z del sistema de particulas actual
void MainWindow::on_SourceVarZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSourceVar(ui->SourceVarXInput->value(), ui->SourceVarYInput->value(), arg1);
        ui->SourceVarZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la direccion en X del sistema de particulas actual
void MainWindow::on_DirXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDir(arg1, ui->DirYInput->value(), ui->DirZInput->value());
        ui->DirXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la direccion en Y del sistema de particulas actual
void MainWindow::on_DirYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDir(ui->DirXInput->value(), arg1, ui->DirZInput->value());
        ui->DirYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la direccion en Z del sistema de particulas actual
void MainWindow::on_DirZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDir(ui->DirXInput->value(), ui->DirYInput->value(), arg1);
        ui->DirZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en X del sistema de particulas actual
void MainWindow::on_DirVarXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDirVar(arg1, ui->DirVarYInput->value(), ui->DirVarZInput->value());
        ui->DirVarXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en Y del sistema de particulas actual
void MainWindow::on_DirVarYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDirVar(ui->DirVarXInput->value(), arg1, ui->DirVarZInput->value());
        ui->DirVarYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del origen en Z del sistema de particulas actual
void MainWindow::on_DirVarZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setDirVar(ui->DirVarXInput->value(), ui->DirVarYInput->value(), arg1);
        ui->DirVarZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el tamaño en X de las particulas del sistema actual
void MainWindow::on_SizeXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSize(arg1, ui->SizeYInput->value(), ui->SizeZInput->value());
        ui->SizeXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el tamaño en Y de las particulas del sistema actual
void MainWindow::on_SizeYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSize(ui->SizeXInput->value(), arg1, ui->SizeZInput->value());
        ui->SizeYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el tamaño en Z de las particulas del sistema actual
void MainWindow::on_SizeZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSize(ui->SizeXInput->value(), ui->SizeYInput->value(), arg1);
        ui->SizeZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del tamaño en X de las particulas del sistema actual
void MainWindow::on_SizeVarXInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSizeVar(arg1, ui->SizeVarYInput->value(), ui->SizeVarZInput->value());
        ui->SizeVarXInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del tamaño en Y de las particulas del sistema actual
void MainWindow::on_SizeVarYInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSizeVar(ui->SizeVarXInput->value(), arg1, ui->SizeVarZInput->value());
        ui->SizeVarYInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del tamaño en Z de las particulas del sistema actual
void MainWindow::on_SizeVarZInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setSizeVar(ui->SizeVarXInput->value(), ui->SizeVarYInput->value(), arg1);
        ui->SizeVarZInput->setSingleStep(arg1 * 0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera el TTL del sistema de particulas actual
void MainWindow::on_TTLInput_valueChanged(int arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setTimeToLive(arg1);
        ui->TTLInput->setSingleStep(int(float(arg1)*0.1));
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto altera la varianza del TTL del sistema de particulas actual
void MainWindow::on_TTLVarInput_valueChanged(int arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setTimeToLiveVar(arg1);
        ui->TTLVarInput->setSingleStep(int(float(arg1)*0.1));
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto permite abrir el selector de color
void MainWindow::on_ColorGradientButton_clicked()
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        ColorGradientPicker* CGP= new ColorGradientPicker();
        CGP->Initialize(P->getStartColor(), P->getEndColor());

        // Conexiones para vista previa
        connect(CGP, SIGNAL(StartColorChanged(vec4)), this, SLOT(ChangeParticleSColor(vec4)));
        connect(CGP, SIGNAL(EndColorChanged(vec4)), this, SLOT(ChangeParticleEColor(vec4)));

        CGP->show();
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Para cambiar dinamicamente los colores del sistema de particulas actual
void MainWindow::ChangeParticleSColor(vec4 s)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setStartColor(s.x, s.y, s.z, s.w);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse para el preview.");
}

void MainWindow::ChangeParticleEColor(vec4 e)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setEndColor(e.x, e.y, e.z, e.w);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse para el preview.");
}

// Esto permitira especificar una nueva textura para la particula
void MainWindow::on_LoadParticleTextureButton_clicked()
{
    QString FileURL= QFileDialog::getOpenFileName(this,
                                                  "Escoger nueva textura...",
                                                  "../");

    if (FileURL!="")
    {
        qDebug("getOpenFileName says: %s", FileURL.toStdString().c_str());

        // Actualicemos
        if (!ui->ViewPort->ChangeParticleTexture(ui->SystemList->currentText(), FileURL))
            printf("No se pudo cargar la textura.");
        else
        {
            QStringList t= FileURL.split("/");

            ui->TextureInput->setText(t.at(t.size()-1));
        }
    }
    else
        printf("No se escogio nueva textura.\n");

}

// Para cambiar dinamicamente el blending del sistema de particulas actual
void MainWindow::on_SrcBlendingInput_currentIndexChanged(int index)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
        P->setSrcBlending(index);
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Para cambiar dinamicamente el blending del sistema de particulas actual
void MainWindow::on_DstBlendingInput_currentIndexChanged(int index)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
        P->setDstBlending(index);
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Para cambiar dinamicamente la funcion alfa del sistema de particulas actual
void MainWindow::on_AlphaFunctionInput_currentIndexChanged(int index)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
        P->setAlphaFunction(index);
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Para cambiar dinamicamente el valor de referencia de la funcion alfa del
// sistema de particulas actual
void MainWindow::on_AlphaRefInput_valueChanged(double arg1)
{
    ParticleSystem* P= ui->ViewPort->getPartSystemByName(ui->SystemList->currentText());

    if (P!= NULL)
    {
        P->setAlphaReference(arg1);
        ui->AlphaRefInput->setSingleStep(arg1*0.1);
    }
    else
        printf("ERROR: No se pudo reconstruir el sistema. No pudo encontrarse.");
}

// Esto abrira el editor de mapa de alturas
void MainWindow::on_actionOpenHeightmapEditor_triggered()
{
    TerrainHeightMapper* TEditor= new TerrainHeightMapper();

    TEditor->show();
}
